﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Data.Linq;
using System.Web.Helpers;
using projectManagementWeb.Models.Developer;
using projectManagementWeb.Models;

namespace projectManagementWeb.Controllers
{
    /// <summary>
    /// This class encapsulates all the functionality from the Developer Module
    /// of the system.
    /// </summary>
    public class DeveloperController : Controller
    {

        #region Fields

        /// <summary>
        /// Connection with Database
        /// </summary>
        private projectmanagementDBDataContext _dbContext;

        #endregion
        //
        // GET: /Developer/

        public ActionResult Index()
        {
            return View();
        }

        /// <summary>
        /// Constructor
        /// </summary>
        public DeveloperController()
        {
            Init();
        }

        /// <summary>
        /// Placeholder method to connect to the database
        /// </summary>
        private void Init()
        {
            try
            {
                _dbContext = new projectmanagementDBDataContext();
            }
            catch (Exception)
            {
                return;
            }
        }

        #region Developer Logic Methods


        public DeveloperReportModel CreateDeveloperReport(string username)
        {
            return null;
        }

        public SortedList<int,string> GetAllowedStatusFlags(string username)
        {
            SortedList<int,string> allowedStatus = new SortedList<int,string>();

            ISingleResult<spGetAllowedStatusFlagsResult> result = _dbContext.spGetAllowedStatusFlags(username);
            foreach (spGetAllowedStatusFlagsResult flag in result)
            {
                allowedStatus.Add(flag.ID,flag.name);
            }

            return allowedStatus;
        }

        public List<TaskProgressUpdateModel> GetDeveloperProgress(string username)
        {
            return null;
        }


        public List<TaskDescriptionModel> GetTasks(string username, bool progressTasks)
        {
            List<TaskDescriptionModel> tasksResult = new List<TaskDescriptionModel>();
          

            ISingleResult<spGetUserTasksResult> tasks = _dbContext.spGetUserTasks(username);

            foreach (spGetUserTasksResult task in tasks)
            {
                if (task.tStatusID == 17)
                    continue;
                TaskDescriptionModel realTask = new TaskDescriptionModel();
                realTask.TaskID = task.ID;
                realTask.TaskName = task.name;
                realTask.StartDate = task.startDate;
                realTask.EndDate = task.endDate;
                realTask.PlannedEstimate = (int)task.taskEffortPlanned;
                realTask.CurrentEffortDone = (int)task.taskRealEffort;
                realTask.CurrentEffortPending = (int)task.taskEffortPending;
                realTask.CurrentStatus = (int)task.tStatusID;
                realTask.ProjectID = task.projectID;

                ISingleResult<spGetProjectByIDResult> projectRegister = _dbContext.spGetProjectByID(task.projectID);

                foreach (spGetProjectByIDResult project in projectRegister)
                {
                    realTask.ProjectName = project.name;
                    break;
                }
                
                
                //Get the module for the Task
                ISingleResult<spGetTaskModuleResult> moduleResult =  _dbContext.spGetTaskModule(task.ID);
                foreach (spGetTaskModuleResult module in moduleResult)
                {
                  realTask.ModuleName = module.name;
                  realTask.ModuleID = module.ID;
                }
                if (progressTasks == true)
                {
                    if ((task.tStatusID == 10) || (task.tStatusID == 15) || (task.tStatusID == 19))
                    {
                        tasksResult.Add(realTask);
                    }
                }
                else
                {
                    tasksResult.Add(realTask);
                }                
            }
            return tasksResult;
        }



        public List<TaskDescriptionModel> GetTasks2(string username, bool progressTasks, int projectID)
        {
            List<TaskDescriptionModel> tasksResult = new List<TaskDescriptionModel>();


            ISingleResult<spGetUserTasksResult> tasks = _dbContext.spGetUserTasks(username);

            foreach (spGetUserTasksResult task in tasks)
            {
                if (task.tStatusID == 17)
                    continue;
                TaskDescriptionModel realTask = new TaskDescriptionModel();
                realTask.TaskID = task.ID;
                realTask.TaskName = task.name;
                realTask.StartDate = task.startDate;
                realTask.EndDate = task.endDate;
                realTask.PlannedEstimate = (int)task.taskEffortPlanned;
                realTask.CurrentEffortDone = (int)task.taskRealEffort;
                realTask.CurrentEffortPending = (int)task.taskEffortPending;
                realTask.CurrentStatus = (int)task.tStatusID;
                realTask.ProjectID = task.projectID;

                ISingleResult<spGetProjectByIDResult> projectRegister = _dbContext.spGetProjectByID(task.projectID);

                foreach (spGetProjectByIDResult project in projectRegister)
                {
                    realTask.ProjectName = project.name;
                    break;
                }


                //Get the module for the Task
                ISingleResult<spGetTaskModuleResult> moduleResult = _dbContext.spGetTaskModule(task.ID);
                foreach (spGetTaskModuleResult module in moduleResult)
                {
                    realTask.ModuleName = module.name;
                    realTask.ModuleID = module.ID;
                }
                if (progressTasks == true)
                {
                    if ((task.tStatusID == 10) || (task.tStatusID == 15) || (task.tStatusID == 19))
                    {
                        if (task.projectID == projectID)
                        {
                            tasksResult.Add(realTask);
                        }
                    }
                }
                else
                {
                    tasksResult.Add(realTask);
                }
            }
            return tasksResult;
        }

        
        public UserDataModel GetUserData(string username)
        {
            UserDataModel user = new UserDataModel();

            ISingleResult<aspnet_User> result = _dbContext.spGetUser(username);
            foreach (aspnet_User userResult in result)
            {
                user.UserCompleteName = userResult.FirstName + " " + userResult.LastName;
                user.UserName = username;

            }
            return user;
        }

        public bool ReportEffort(int newStatus, int effortPending, int effortDone, int taskID)
        {
            try
            {
                _dbContext.spReportEffortinTask((int?)taskID, effortDone, effortPending, newStatus);
            }
            catch (Exception )
            {
                return false;
            }
            return true;
        }

        public bool UpdateTaskStatus(string newStatus, uint taskID)
        {
            return false;
        }

        #endregion

        [AcceptVerbs(HttpVerbs.Get)]
        public ActionResult DeveloperReportsForm()
        {
            int userId = _dbContext.spGetUser(User.Identity.Name).First().id;

            var projectList = _dbContext.spGetAssignedProjectsByUserID(userId).ToList(); //todo change to byProjectLeader
            ViewBag.projectList = projectList;

            return View();
        }

        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult DeveloperReportsForm(DeveloperReportFormModel model)
        {
            if (ModelState.IsValid)
            {        
                if (model.reportType.Equals("ValorGanado"))
                {
                    return RedirectToAction("EVChart", model);
                }
                else if (model.reportType.Equals("Tareas"))
                {
                    return RedirectToAction("TaskProgressChart", model);
                }
            }

            return RedirectToAction("Index", model);
        }

        public ActionResult DeveloperTasksForm()
        {
            TaskListModel taskList = new TaskListModel();
            taskList.taskList = this.GetTasks(User.Identity.Name,false);

            
            return View(taskList);     
        }

        [HttpPost]
        public ActionResult DeveloperTasksForm(TaskListModel model)
        {
            if (ModelState.IsValid)
            {
                if (model.taskList != null)
                {
                    foreach (TaskDescriptionModel task in model.taskList)
                    {

                        this.ReportEffort(task.CurrentStatus, task.CurrentEffortPending, task.CurrentEffortDone, task.TaskID);
                    }
                }
            }

            // If we got this far, something failed, redisplay form
            return View(model);
        }

        public ActionResult TaskDescription(int taskID)
        {
            ISingleResult<spGetTaskResult> tasks = _dbContext.spGetTask(taskID);           
            TaskDescriptionModel model = new TaskDescriptionModel();

            foreach (spGetTaskResult task in tasks)
            {
                model.TaskID = taskID;
                model.TaskName = task.name;
                model.TaskDescription = task.description;
                model.StartDate = task.startDate;
                model.EndDate = task.endDate;
                model.CurrentEffortDone = (int)task.taskRealEffort;
                model.CurrentEffortPending = (int)task.taskEffortPending;
                model.PlannedEstimate = (int)task.taskEffortPlanned;

                try { 
                    //Get the status for the Task
                    ISingleResult<spGetStatusNameResult> statusName = _dbContext.spGetStatusName(task.tStatusID);
                    model.CurrentStatusName = statusName.First().name;
                    if (task.tStatusID == 16 || task.tStatusID == 20)
                    {
                        ViewBag.status = "completed";
                        model.RealEndDate = (DateTime)task.realEndDate;
                    }
                    else
                    {
                        ViewBag.status = "Notcompleted";
                    }
                }
                catch (InvalidOperationException)
                {
                    //Do nothing
                }

                //Get the module for the Task
                try
                {
                    ISingleResult<spGetTaskModuleResult> moduleName = _dbContext.spGetTaskModule(taskID);
                    model.ModuleName = moduleName.First().name;
                }
                catch (InvalidOperationException )
                {
                    //Do nothing
                }

                //Get the project for the Task
                try
                {
                    ISingleResult<spGetTaskProjectResult> projectName = _dbContext.spGetTaskProject(taskID);
                    model.ProjectName = projectName.First().name;
                }
                catch (InvalidOperationException )
                {
                    //Do nothing
                }
                
                
            }

            return View(model);
        }

        #region Developer Reports Logic Methods

        public ActionResult TaskProgressChart(DeveloperReportFormModel model)
        {
            if (ModelState.IsValid)
            {

                List<string> id = new List<string>();
                List<int> ee = new List<int>();
                List<int> er = new List<int>();
                List<int> ef = new List<int>();
                String[] xLabel = { " ", "Total de tareas" };
                int[] eeTot = new int[2] { 0, 0 };
                int[] erTot = new int[2] { 0, 0 };
                int[] efTot = new int[2] { 0, 0 };
                int index = 1;
                float width_chart = 0;
                DateTime today = DateTime.Today;
                DateTime startDate = DateTime.Today; ;
                ViewBag.ValidDate = "true";

                try {
                    startDate = (DateTime)_dbContext.spGetProjectStartDate(model.projectID).First().startDate;
                    ViewBag.project = 1;
                }
                catch (Exception){
                    ViewBag.project = 0;
                    return View();
                }
                

                if (startDate.Date > today.Date)
                {
                    ViewBag.ValidDate = "false";
                    ViewBag.startDate = startDate;
                    return View();
                }


                TaskListModel taskList = new TaskListModel();
                taskList.taskList = this.GetTasks2(User.Identity.Name, true, model.projectID);

                int userId = _dbContext.spGetUser(User.Identity.Name).First().id;
                ISingleResult<spTasksInProgressDevResult> progressTasks = _dbContext.spTasksInProgressDev(userId, model.projectID);

                foreach (spTasksInProgressDevResult progressTask in progressTasks)
                {
                    id.Add(" ");
                    id.Add("#" + index.ToString());
                    index = index + 1;
                    //id.Add(" " + progressTask.ID);                    

                    ee.Add((int)progressTask.taskEffortPlanned);
                    ee.Add(0);

                    er.Add(0);
                    er.Add((int)progressTask.taskRealEffort);

                    ef.Add(0);
                    ef.Add((int)progressTask.taskEffortPending);

                    eeTot[0] = eeTot[0] + (int)progressTask.taskEffortPlanned;
                    erTot[1] = erTot[1] + (int)progressTask.taskRealEffort;
                    efTot[1] = efTot[1] + (int)progressTask.taskEffortPending;
                }
                if (model.detail.Equals("Individual"))
                {
                    if (id.Count == 0)
                    {
                        id.Add("0 tareas en progreso");
                        ee.Add(0);
                        er.Add(0);
                        ef.Add(0);
                    }

                    if (id.Count < 8) width_chart = 800;
                    else
                    {
                        width_chart = (float)id.Count() / 8;
                        width_chart = width_chart * 800;
                    }

                    var chart = new Chart(width: (int)width_chart, height: 600, theme: ChartTheme.Blue)
                        .AddTitle("Tareas en progreso individuales")
                        .AddSeries(chartType: "StackedColumn",
                        xValue: id,
                        yValues: ee,
                        name: "Esfuerzo estimado")
                        .AddSeries(chartType: "StackedColumn",
                        xValue: id,
                        yValues: er,
                        name: "Esfuerzo real")
                        .AddSeries(chartType: "StackedColumn",
                        xValue: id,
                        yValues: ef,
                        name: "Esfuerzo faltante")
                        .AddLegend()
                        .SetXAxis(title: "# de tarea")
                        .SetYAxis(title: "Tiempo (horas)")
                        //.Write();
                        .GetBytes("jpeg");
                    //return View(model);
                    //return File(chart, "image/jpeg");

                    var base64Data = Convert.ToBase64String(chart);
                    ViewBag.ImageData = base64Data;
                    ViewBag.ImageContentType = "image/jpeg";

                    return View(taskList);
                }
                else if (model.detail.Equals("Total"))
                {
                    if (id.Count == 0)
                    {
                        xLabel[0] = " ";
                        xLabel[1] = "0 tareas en progreso";
                    }
                    var chart = new Chart(width: 800, height: 600, theme: ChartTheme.Blue)
                         .AddTitle("Total de tareas en progreso")
                         .AddSeries(chartType: "StackedColumn",
                         xValue: xLabel,
                         yValues: eeTot,
                         name: "Esfuerzo estimado total")
                         .AddSeries(chartType: "StackedColumn",
                         xValue: xLabel,
                         yValues: erTot,
                         name: "Esfuerzo real total")
                         .AddSeries(chartType: "StackedColumn",
                         xValue: xLabel,
                         yValues: efTot,
                         name: "Esfuerzo faltante total")
                         .AddLegend()
                         .SetXAxis(title: "Tareas")
                         .SetYAxis(title: "Tiempo (horas)")
                        //.Write();
                         .GetBytes("jpeg");

                    //return View(model);
                    //return File(chart, "image/png");

                    var base64Data = Convert.ToBase64String(chart);
                    ViewBag.ImageData = base64Data;
                    ViewBag.ImageContentType = "image/jpeg";

                    return View(taskList);

                }

            }
            return View(model);
        }

        public ActionResult EVChart(DeveloperReportFormModel model)
        {
            
            if (ModelState.IsValid)
            {
                DateTime today = DateTime.Today;
                DateTime startDate = DateTime.Today;
                DateTime endDate = DateTime.Today;
                DateTime startDateBL = DateTime.Today;
                DateTime endDateBL = DateTime.Today;
                DateTime reportDate = startDate;
                DateTime stopDate;
                float width_chart= 0;
                int index = 1;
                TimeSpan tempSize;
                int userId = 0;
                ViewBag.ValidDate = "true";
              
                try {
                    
                    startDate = (DateTime)_dbContext.spGetProjectStartDate(model.projectID).First().startDate;
                    endDate = (DateTime)_dbContext.spGetProjectStartDate(model.projectID).First().endDate;
                    ViewBag.project = 1;
                }
                catch (Exception)
                {
                    ViewBag.project = 0;
                }

                try
                {
                    userId = _dbContext.spGetUser(User.Identity.Name).First().id;
                }
                catch (Exception)
                {
                    //Do nothing
                } 

                ISingleResult<spEVdevResult> developerTasks = _dbContext.spEVdev(userId, model.projectID);
                ISingleResult<spEVdevResult> developerTasks2 = _dbContext.spEVdev(userId, model.projectID);
                ISingleResult<spdevBaseLineResult> developerTasksBL = _dbContext.spdevBaseLine(userId, model.projectID);
                ISingleResult<spdevBaseLineResult> developerTasksBL2 = _dbContext.spdevBaseLine(userId, model.projectID);
                ViewBag.fechaFin = endDate;
                foreach (spEVdevResult devTask2 in developerTasks2)
                {
                    if (devTask2.tStatusID == 16 || devTask2.tStatusID == 20) {
                        if (devTask2.realEndDate.Value.Date > endDate.Date)
                        {
                            endDate = (DateTime)devTask2.realEndDate;
                        }
                    }

                }

                foreach (spdevBaseLineResult devTaskBL2 in developerTasksBL2)
                {
                    if (devTaskBL2.endDateBaseLine > endDate)
                    {
                        endDate = (DateTime)devTaskBL2.endDateBaseLine;
                    }
                    if (devTaskBL2.startDateBaseLine < startDate)
                    {
                        startDate = (DateTime)devTaskBL2.startDateBaseLine;
                    }

                }

                if (startDate.Date > today.Date)
                {
                    ViewBag.ValidDate = "false";
                    ViewBag.startDate = startDate;
                    return View();
                }

                if (endDate.Date >= today.Date)
                {
                    tempSize = today.Subtract(startDate);
                    stopDate = today;
                }
                else
                {
                    tempSize = endDate.Subtract(startDate);
                    stopDate = endDate;
                }

                int size;
                if ((tempSize.Days % 7) == 0)
                {
                    size = ((tempSize.Days) / 7) + 1;
                }
                else
                {
                    size = ((tempSize.Days) / 7) + 2;
                } 
                
                float[] estadisticas = new float[5];

                float[] pv = new float[size];
                float[] ev = new float[size];
                float[] ac = new float[size];
                float[] bl = new float[size];
                float[] pvP = new float[size];
                float[] evP = new float[size];
                float[] acP = new float[size];
                float[] blP = new float[size];
                DateTime[] fechas = new DateTime[size];
                String[] fechas2 = new String[size];
                fechas[0] = startDate.Date;
                for (int i = 1; i < size; i++)
                {
                    if (fechas[i - 1].AddDays(7).Date < stopDate.Date)
                    {
                        fechas[i] = fechas[i - 1].AddDays(7).Date;
                    }
                    else
                    {
                        fechas[i] = stopDate.Date;
                    }                   
                }
                
                for (int i = 0; i < size; i++)
                {
                    pv[i] = 0;
                    ev[i] = 0;
                    ac[i] = 0;
                    bl[i] = 0;
                    pvP[i] = 0;
                    evP[i] = 0;
                    acP[i] = 0;
                    blP[i] = 0;
                }

                float eac = 0;

                //String[] xLabel = { "Inicio proyecto", "Fecha: " + reportDate };

                foreach (spEVdevResult devTask in developerTasks)
                {
                    reportDate = startDate;
                    reportDate = reportDate.AddDays(7);
                    eac = eac + (float)devTask.taskEffortPlanned;

                    if (devTask.tStatusID != 17) 
                    {
                    if (devTask.endDate.Date <= stopDate.Date) {
                        while (devTask.endDate.Date > reportDate.Date)
                        {
                            reportDate = reportDate.AddDays(7);
                            index = index + 1;
                        }
                        pv[index] = pv[index] + (float)devTask.taskEffortPlanned;
                    } 
                    }


                    index = 1;

                    if (devTask.tStatusID == 16 || devTask.tStatusID == 20)
                    {
                        reportDate = startDate;
                        reportDate = reportDate.AddDays(7);
                        if (devTask.realEndDate.Value.Date <= stopDate.Date)
                        {
                            while (devTask.realEndDate.Value.Date > reportDate.Date)
                            {
                                reportDate = reportDate.AddDays(7);
                                index = index + 1;
                            }
                            ev[index] = ev[index] + (float)devTask.taskEffortPlanned;
                            ac[index] = ac[index] + (float)devTask.taskRealEffort;
                        }
        
                       
                    }
                    index = 1;            
                    
                }

                foreach (spdevBaseLineResult developerTaskBL in developerTasksBL)
                {
                    reportDate = startDate;
                    reportDate = reportDate.AddDays(7);

                    if (developerTaskBL.endDateBaseLine.Value <= stopDate.Date)
                    {
                        while (developerTaskBL.endDateBaseLine.Value.Date > reportDate.Date)
                        {
                            reportDate = reportDate.AddDays(7);
                            index = index + 1;
                        }
                        bl[index] = bl[index] + (float)developerTaskBL.taskEffortBaseLine;
                    }

                    index = 1;

                }

                for (int i = 1; i < size; i++)
                {
                    pv[i] = pv[i] + pv[i - 1];
                    ev[i] = ev[i] + ev[i - 1];
                    ac[i] = ac[i] + ac[i - 1];
                    bl[i] = bl[i] + bl[i - 1];
                }

                if (size < 40) width_chart = 800;
                else
                {
                    width_chart = (float)size / 40;
                    width_chart = width_chart * 800;
                }

                if (model.units.Equals("Horas"))
                {
                    var chart = new Chart(width: (int)width_chart, height: 600, theme: ChartTheme.Blue)
                         .AddTitle("Valor ganado en horas de contrucción")


                         .AddSeries(chartType: "Line",
                         //xValue: xLabel,
                         yValues: pv,
                         name: "Valor planeado")

                         .AddSeries(chartType: "Line",
                        // xValue: xLabel,
                         yValues: bl,
                         name: "Línea base")  

                         .AddSeries(chartType: "Line",
                         //xValue: xLabel,
                         yValues: ev,
                         name: "Valor ganado")
                         .AddSeries(chartType: "Line",
                        // xValue: xLabel,
                         yValues: ac,
                         name: "Costo actual")
                         .AddLegend()
                         .SetXAxis(title: "Periodo de tiempo (semanas)")
                         .SetYAxis(title: "Avance en horas")
                        //.Write();
                          .GetBytes("jpeg");
                    //return File(chart, "image/png");

                    var base64Data = Convert.ToBase64String(chart);
                    ViewBag.ImageData = base64Data;
                    ViewBag.ImageContentType = "image/jpeg";
                    ViewBag.Symbol = "hrs.";
                    ViewBag.PV = pv;
                    ViewBag.EV = ev;
                    ViewBag.AC = ac;
                    ViewBag.BL = bl;

                }
                else if (model.units.Equals("Porcentaje"))
                {
                   
                    if (eac != 0)
                    {
                        for (int i = 0; i < size; i++)
                        {
                            pvP[i] = (pv[i] / eac) * 100;
                            evP[i] = (ev[i] / eac) * 100;
                            acP[i] = (ac[i] / eac) * 100;
                            blP[i] = (bl[i] / eac) * 100;
                        }
                    }

                    var chart = new Chart(width: (int)width_chart, height: 600, theme: ChartTheme.Blue)
                          .AddTitle("Valor ganado en porcentaje")

                          .AddSeries(chartType: "Line",
                         // xValue: xLabel,
                          yValues: pvP,
                          name: "Valor planeado")

                         .AddSeries(chartType: "Line",
                        // xValue: xLabel,
                          yValues: blP,
                          name: "Línea base")

                          .AddSeries(chartType: "Line",
                         // xValue: xLabel,
                          yValues: evP,
                          name: "Valor ganado")
                          .AddSeries(chartType: "Line",
                         // xValue: xLabel,
                          yValues: acP,
                          name: "Costo actual")
                          .AddLegend()
                          .SetXAxis(title: "Periodo de tiempo (semanas)")
                          .SetYAxis(title: "Avance en porcentaje (%)")
                        //.Write();
                          .GetBytes("jpeg");
                    //return File(chart, "image/png");

                    var base64Data = Convert.ToBase64String(chart);
                    ViewBag.ImageData = base64Data;
                    ViewBag.ImageContentType = "image/jpeg";
                    ViewBag.Symbol = "%";
                    ViewBag.PV = pvP;
                    ViewBag.EV = evP;
                    ViewBag.AC = acP;
                    ViewBag.BL = blP;
                }

                // Calculando valores estadísticos
                estadisticas[0] = eac;
                estadisticas[1] = ev[size - 1] - ac[size - 1]; // Varianza costo
                estadisticas[2] = ev[size - 1] - pv[size - 1]; // varianza calendario
                if (ac[size - 1] == 0) estadisticas[3] = 0;
                else estadisticas[3] = ev[size - 1] / ac[size - 1]; // indice de costo
                if (pv[size - 1] == 0) estadisticas[4] = 0;
                else estadisticas[4] = ev[size - 1] / pv[size - 1]; // indice calendario

                ViewBag.fechas = fechas;
                ViewBag.size = fechas.Count();
                ViewBag.estadisticas = estadisticas;
                
                return View();

            }
            return RedirectToAction("Index");
        }

        #endregion

    }
}
